home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / net_src.arc / nrcmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-08  |  26.4 KB  |  1,257 lines

  1. /* net/rom user command processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include "global.h"
  8. #include "config.h"
  9. #include "mbuf.h"
  10. #include "ax25.h"
  11. #include "timer.h"
  12. #include "iface.h"
  13. #include "lapb.h"
  14. #include "netrom.h"
  15. #include "nr4.h"
  16. #include "netuser.h"
  17. #include "tcp.h"
  18. #include "ftp.h"
  19. #include "telnet.h"
  20. #include "finger.h"
  21. #include "ax_mbx.h"
  22. #include "cmdparse.h"
  23. #include "session.h"
  24. #include <ctype.h>
  25.  
  26. #undef NRDEBUG
  27.  
  28. extern struct session *current;
  29.  
  30. char *Nr4states[] = {
  31.     "Disconnected",
  32.     "Conn Pending",
  33.     "Connected",
  34.     "Disc Pending"
  35. } ;
  36.  
  37. char *Nr4reasons[] = {
  38.     "Normal",
  39.     "By Peer",
  40.     "Timeout",
  41.     "Reset",
  42.     "Refused"
  43. } ;
  44.  
  45. static int dointerface(), dobcnodes(), donodetimer(), donrroute(),
  46.            donrttl(), doobsotimer(), donodefilter(), donrverbose(),
  47.            donrconnect(), donrreset(), donrwindow(), donrirtt(),
  48.            donracktime(), donrqlimit(), donrchoketime(), donrretries(),
  49.            donrstatus(), donrkick() ;
  50.  
  51. static struct cmds nrcmds[] = {
  52.     "acktime",    donracktime,    0,    NULLCHAR,    NULLCHAR,
  53.     "bcnodes",    dobcnodes,    2,    "netrom bcnodes <interface>", NULLCHAR,
  54.     
  55. /* Put connect before choketime to make it the default expansion of 'c' */
  56.  
  57.     "connect",    donrconnect,2,    "netrom connect <node>",    NULLCHAR,
  58.     "choketime",    donrchoketime,    0,    NULLCHAR,    NULLCHAR,
  59.     "interface",    dointerface,    4,
  60.         "netrom interface <interface> <alias> <quality>",    NULLCHAR,
  61.     "irtt",            donrirtt,        0,    NULLCHAR,    NULLCHAR,
  62.     "kick",            donrkick,        2,    "netrom kick <&nrcb>",    NULLCHAR,
  63.     "nodefilter",    donodefilter,    0,    NULLCHAR,    NULLCHAR,
  64.     "nodetimer",    donodetimer,    0,    NULLCHAR,    NULLCHAR,
  65.     "obsotimer",    doobsotimer,    0,    NULLCHAR,    NULLCHAR,
  66.     "qlimit",    donrqlimit,    0,    NULLCHAR,    NULLCHAR,
  67.     "reset",    donrreset,    2,    "netrom reset <&nrcb>",    NULLCHAR,
  68.     "retries",    donrretries,0,    NULLCHAR,    NULLCHAR,
  69.     "route",    donrroute,    0,    NULLCHAR,    NULLCHAR,
  70.     "status",    donrstatus,    0,    NULLCHAR,    NULLCHAR,
  71.     "ttl",        donrttl,    0,    NULLCHAR,    NULLCHAR,
  72.     "verbose",    donrverbose,0,    NULLCHAR,    NULLCHAR,
  73.     "window",    donrwindow,    0,    NULLCHAR,    NULLCHAR,
  74.     NULLCHAR,    NULLFP,        0,
  75.         "netrom subcommands: acktime bcnodes connect choketime interface irtt kick\n                    nodetimer nodefilter obsotimer qlimit reset retries route\n                    status ttl verbose window",
  76.         NULLCHAR
  77. } ;
  78.  
  79. static struct timer nodetimer ;    /* timer for nodes broadcasts */
  80. static struct timer obsotimer ;    /* timer for aging routes */
  81.  
  82. /* Command multiplexer */
  83. donetrom(argc,argv)
  84. int argc ;
  85. char *argv[] ;
  86. {
  87.     return subcmd(nrcmds,argc,argv) ;
  88. }
  89.  
  90. static int dorouteadd(), doroutedrop(), doroutedump(), dorouteinfo() ;
  91.  
  92. static struct cmds routecmds[] = {
  93.     "add",    dorouteadd,    6,
  94.         "netrom route add <alias> <destination> <interface> <quality> <neighbor>",
  95.         "add failed",
  96.     "drop",    doroutedrop, 4,
  97.         "netrom route drop <destination> <neighbor> <interface>",
  98.         "drop failed",
  99.     "info", dorouteinfo, 2,
  100.         "netrom route info <destination>", NULLCHAR,
  101.     NULLCHAR,    NULLFP,    0,
  102.         "netrom route subcommands: add drop info",
  103.         NULLCHAR
  104. } ;
  105.  
  106. /* Route command multiplexer */
  107. static
  108. donrroute(argc, argv)
  109. int argc ;
  110. char *argv[] ;
  111. {
  112.     if (argc < 2) {
  113.         doroutedump() ;
  114.         return 0 ;
  115.     }
  116.     return subcmd(routecmds,argc,argv) ;
  117. }
  118.  
  119. /* Dump a list of known routes */
  120. static
  121. doroutedump()
  122. {
  123.     register struct nrroute_tab *rp ;
  124.     register int i, column ;
  125.     char buf[16] ;
  126.     char *cp ;
  127.     
  128.     column = 1 ;
  129.     
  130.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  131.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  132.             strcpy(buf,rp->alias) ;
  133.             /* remove trailing spaces */
  134.             if ((cp = index(buf,' ')) == NULLCHAR)
  135.                 cp = &buf[strlen(buf)] ;
  136.             if (cp != buf)        /* don't include colon for null alias */
  137.                 *cp++ = ':' ;
  138.             pax25(cp,&rp->call) ;
  139.             printf("%-16s  ",buf) ;
  140.             if (column++ == 4) {
  141.                 printf("\n") ;
  142.                 column = 1 ;
  143.             }
  144.         }
  145.  
  146.     if (column != 1)
  147.         printf("\n") ;
  148.         
  149.     return 0 ;
  150. }
  151.  
  152. /* print detailed information on an individual route */
  153. static int
  154. dorouteinfo(argc,argv)
  155. int argc ;
  156. char *argv[] ;
  157. {
  158.     register struct nrroute_tab *rp ;
  159.     register struct nr_bind *bp ;
  160.     register struct nrnbr_tab *np ;
  161.     struct ax25_addr dest ;
  162.     char neighbor[60] ;
  163.  
  164.     if (setcall(&dest,argv[1]) == -1) {
  165.         printf ("bad destination name\n") ;
  166.         return -1 ;
  167.     }
  168.         
  169.     if ((rp = find_nrroute(&dest)) == NULLNRRTAB) {
  170.         printf("no such route\n") ;
  171.         return -1 ;
  172.     }
  173.  
  174.     for (bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
  175.         np = bp->via ;
  176.         psax25(neighbor,np->call) ;
  177.         printf("%1s %3d  %3d  %-8s  %s\n",
  178.                 (bp->flags & NRB_PERMANENT ? "P" :
  179.                  bp->flags & NRB_RECORDED ? "R" : " "),
  180.                 bp->quality,bp->obsocnt,
  181.                 nrifaces[np->interface].interface->name,
  182.                 neighbor) ;
  183.     }
  184.     return 0 ;
  185. }
  186.         
  187. /* convert a null-terminated alias name to a blank-filled, upcased */
  188. /* version.  Return -1 on failure. */
  189. static int
  190. putalias(to,from,complain)
  191. register char *to, *from ;
  192. int complain ;
  193. {
  194.     int len, i ;
  195.     
  196.     if ((len = strlen(from)) > ALEN) {
  197.         if (complain)
  198.             printf ("alias too long - six characters max\n") ;
  199.         return -1 ;
  200.     }
  201.     
  202.     for (i = 0 ; i < ALEN ; i++) {
  203.         if (i < len) {
  204.             if (islower(*from))
  205.                 *to++ = toupper(*from++) ;
  206.             else
  207.                 *to++ = *from++ ;
  208.         }
  209.         else
  210.             *to++ = ' ' ;
  211.     }
  212.             
  213.     *to = '\0' ;
  214.     return 0 ;
  215. }
  216.  
  217. /* Add a route */
  218. static int
  219. dorouteadd(argc, argv)
  220. int argc ;
  221. char *argv[] ;
  222. {
  223.     char alias[7] ;
  224.     struct ax25_addr dest ;
  225.     unsigned quality ;
  226.     char neighbor[AXALEN * 3] ;
  227.     register int i ;
  228.     int naddr ;
  229.  
  230.     /* format alias (putalias prints error message if necessary) */
  231.     if (putalias(alias,argv[1],1) == -1)
  232.         return -1 ;
  233.  
  234.     /* format destination callsign */
  235.     if (setcall(&dest,argv[2]) == -1) {
  236.         printf("bad destination callsign\n") ;
  237.         return -1 ;
  238.     }
  239.  
  240.     /* find interface */
  241.     for (i = 0 ; i < nr_numiface ; i++)
  242.         if (!strcmp(nrifaces[i].interface->name,argv[3]))
  243.             break ;
  244.     if (i == nr_numiface) {
  245.         printf("Interface \"%s\" not found\n",argv[3]) ;
  246.         return -1 ;
  247.     }
  248.     
  249.     /* get and check quality value */
  250.     if ((quality = atoi(argv[4])) > 255) {
  251.         printf("maximum route quality is 255\n") ;
  252.         return -1 ;
  253.     }
  254.  
  255.     /* make sure no more than 2 digis */
  256.     naddr = argc - 5 ;
  257.     if (naddr > 3) {
  258.         printf("no more than 2 digipeaters for a net/rom neighbor\n") ;
  259.         return -1 ;
  260.     }
  261.     
  262.     /* format neighbor address string */
  263.     setpath(neighbor,&argv[5],naddr) ;
  264.  
  265.     return nr_routeadd(alias,&dest,i,quality,neighbor,1,0) ;
  266. }
  267.  
  268.  
  269. /* drop a route */
  270. static
  271. doroutedrop(argc,argv)
  272. int argc ;
  273. char *argv[] ;
  274. {
  275.     struct ax25_addr dest, neighbor ;
  276.     register int i ;
  277.  
  278.     /* format destination and neighbor callsigns */
  279.     if (setcall(&dest,argv[1]) == -1) {
  280.         printf("bad destination callsign\n") ;
  281.         return -1 ;
  282.     }
  283.     if (setcall(&neighbor,argv[2]) == -1) {
  284.         printf("bad neighbor callsign\n") ;
  285.         return -1 ;
  286.     }
  287.  
  288.     /* find interface */
  289.     for (i = 0 ; i < nr_numiface ; i++)
  290.         if (!strcmp(nrifaces[i].interface->name,argv[3]))
  291.             break ;
  292.     if (i == nr_numiface) {
  293.         printf("Interface \"%s\" not found\n",argv[3]) ;
  294.         return -1 ;
  295.     }
  296.  
  297.     return nr_routedrop(&dest,&neighbor,i) ;
  298. }
  299.     
  300.     
  301. /* make an interface available to net/rom */
  302. static int
  303. dointerface(argc,argv)
  304. int argc ;
  305. char *argv[] ;
  306. {
  307.     register char *sp, *dp ;
  308.     int i, len ;
  309.     register struct interface *ifp ;
  310.     extern struct interface *ifaces ;
  311.  
  312.     if (nr_interface == NULLIF) {
  313.         printf("Attach netrom interface first\n") ;
  314.         return 1 ;
  315.     }
  316.     
  317.     if (nr_numiface >= NRNUMIFACE) {
  318.         printf("Only %d net/rom interfaces available\n",NRNUMIFACE) ;
  319.         return 1 ;
  320.     }
  321.     
  322.     for(ifp=ifaces;ifp != NULLIF;ifp = ifp->next){
  323.         if(strcmp(argv[1],ifp->name) == 0)
  324.             break;
  325.     }
  326.     if(ifp == NULLIF){
  327.         printf("Interface \"%s\" unknown\n",argv[1]);
  328.         return 1;
  329.     }
  330.     for (i = 0 ; i < nr_numiface ; i++)
  331.         if (nrifaces[i].interface == ifp) {
  332.             printf("Interface \"%s\" is already registered\n",argv[1]) ;
  333.             return 1 ;
  334.         }
  335.         
  336.     nrifaces[nr_numiface].interface = ifp ;
  337.  
  338.     if (putalias(nrifaces[nr_numiface].alias,argv[2],1) == -1)
  339.         return 1 ;
  340.         
  341.     if ((nrifaces[nr_numiface].quality = atoi(argv[3])) > 255) {
  342.         printf("Quality cannot be greater than 255\n") ;
  343.         return 1 ;
  344.     }
  345.         
  346.     nr_numiface++ ;            /* accept this interface */
  347.     return 0 ;
  348. }
  349.  
  350. /* Broadcast nodes list on named interface. */
  351.  
  352. static int
  353. dobcnodes(argc,argv)
  354. int argc ;
  355. char *argv[] ;
  356. {
  357.     register int i ;
  358.     for (i = 0 ; i < nr_numiface ; i++)
  359.         if (!strcmp(nrifaces[i].interface->name,argv[1]))
  360.             break ;
  361.     if (i == nr_numiface) {
  362.         printf("Interface \"%s\" not found\n",argv[1]) ;
  363.         return 1 ;
  364.     }
  365.         
  366.     nr_bcnodes(i) ;
  367. }
  368.  
  369. #define TICKSPERSEC    (1000L / MSPTICK)    /* Ticks per second */
  370.  
  371. /* Set outbound node broadcast interval */
  372. static int
  373. donodetimer(argc,argv)
  374. int argc;
  375. char *argv[];
  376. {
  377.     int donodetick();
  378.  
  379.     if(argc < 2){
  380.         printf("%lu/%lu\n",
  381.                 (nodetimer.start - nodetimer.count)/TICKSPERSEC,
  382.                 nodetimer.start/TICKSPERSEC);
  383.         return 0;
  384.     }
  385.     stop_timer(&nodetimer) ;    /* in case it's already running */
  386.     nodetimer.func = (void (*)())donodetick;/* what to call on timeout */
  387.     nodetimer.arg = NULLCHAR;        /* dummy value */
  388.     nodetimer.start = atol(argv[1])*TICKSPERSEC;    /* set timer duration */
  389.     start_timer(&nodetimer);        /* and fire it up */
  390.     return 0;
  391. }
  392.  
  393. static int
  394. donodetick()
  395. {
  396.     register int i ;
  397.  
  398.     for (i = 0 ; i < nr_numiface ; i++)
  399.         nr_bcnodes(i) ;
  400.  
  401.     /* Restart timer */
  402.     start_timer(&nodetimer) ;
  403. }
  404.  
  405. /* Set timer for aging routes */
  406. static int
  407. doobsotimer(argc,argv)
  408. int argc;
  409. char *argv[];
  410. {
  411.     extern int doobsotick();
  412.  
  413.     if(argc < 2){
  414.         printf("%lu/%lu\n",(obsotimer.start - obsotimer.count)/TICKSPERSEC,
  415.         obsotimer.start/TICKSPERSEC);
  416.         return 0;
  417.     }
  418.     stop_timer(&obsotimer) ;    /* just in case it's already running */
  419.     obsotimer.func = (void (*)())doobsotick;/* what to call on timeout */
  420.     obsotimer.arg = NULLCHAR;        /* dummy value */
  421.     obsotimer.start = atol(argv[1])*TICKSPERSEC;    /* set timer duration */
  422.     start_timer(&obsotimer);        /* and fire it up */
  423.     return 0;
  424. }
  425.  
  426.  
  427. /* Go through the routing table, reducing the obsolescence count of
  428.  * non-permanent routes, and purging them if the count reaches 0
  429.  */
  430. static int
  431. doobsotick()
  432. {
  433.     register struct nrnbr_tab *np ;
  434.     register struct nrroute_tab *rp, *rpnext ;
  435.     register struct nr_bind *bp, *bpnext ;
  436.     struct ax25_addr neighbor ;
  437.     int i ;
  438.  
  439.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  440.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
  441.             rpnext = rp->next ;     /* save in case we free this route */
  442.             for (bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
  443.                 bpnext = bp->next ;    /* in case we free this binding */
  444.                 if (bp->flags & NRB_PERMANENT)    /* don't age these */
  445.                     continue ;
  446.                 if (--bp->obsocnt == 0) {        /* time's up! */
  447.                     if (bp->next != NULLNRBIND)
  448.                         bp->next->prev = bp->prev ;
  449.                     if (bp->prev != NULLNRBIND)
  450.                         bp->prev->next = bp->next ;
  451.                     else
  452.                         rp->routes = bp->next ;
  453.                     rp->num_routes-- ;            /* one less binding */
  454.                     np = bp->via ;                /* find the neighbor */
  455.                     free(bp) ;                    /* now we can free the bind */
  456.                     /* Check to see if we can free the neighbor */
  457.                     if (--np->refcnt == 0) {
  458.                         if (np->next != NULLNTAB)
  459.                             np->next->prev = np->prev ;
  460.                         if (np->prev != NULLNTAB)
  461.                             np->prev->next = np->next ;
  462.                         else {
  463.                             memcpy(neighbor.call,np->call,ALEN) ;
  464.                             neighbor.ssid = np->call[ALEN] ;
  465.                             nrnbr_tab[nrhash(&neighbor)] = np->next ;
  466.                         }
  467.                         free(np) ;    /* free the storage */
  468.                     }
  469.                 }
  470.             }
  471.             if (rp->num_routes == 0) {        /* did we free them all? */
  472.                 if (rp->next != NULLNRRTAB)
  473.                     rp->next->prev = rp->prev ;
  474.                 if (rp->prev != NULLNRRTAB)
  475.                     rp->prev->next = rp->next ;
  476.                 else
  477.                     nrroute_tab[i] = rp->next ;
  478.  
  479.                 free(rp) ;
  480.             }
  481.         }
  482.     }
  483.  
  484.     start_timer(&obsotimer) ;
  485. }
  486.  
  487.  
  488. static int donfadd(), donfdrop(), donfmode() ;
  489.  
  490. static struct cmds nfcmds[] = {
  491.     "add",    donfadd,    3,
  492.         "netrom nodefilter add <neighbor> <interface>",
  493.         "add failed",
  494.     "drop",    donfdrop,    3,
  495.         "netrom nodefilter drop <neighbor> <interface>",
  496.         "drop failed",
  497.     "mode",    donfmode,    0,    NULLCHAR,    NULLCHAR,
  498.     NULLCHAR,    NULLFP,    0,
  499.         "nodefilter subcommands: add drop mode",
  500.         NULLCHAR
  501. } ;
  502.  
  503. /* nodefilter command multiplexer */
  504. static
  505. donodefilter(argc,argv)
  506. int argc ;
  507. char *argv[] ;
  508. {
  509.     if (argc < 2) {
  510.         donfdump() ;
  511.         return 0 ;
  512.     }
  513.     return subcmd(nfcmds,argc,argv) ;
  514. }
  515.  
  516. /* display a list of <callsign,interface> pairs from the filter
  517.  * list.
  518.  */
  519. static
  520. donfdump()
  521. {
  522.     int i, column = 1 ;
  523.     struct nrnf_tab *fp ;
  524.     char buf[16] ;
  525.  
  526.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  527.         for (fp = nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
  528.             pax25(buf,&fp->neighbor) ;
  529.             printf("%-7s %-8s  ",
  530.                     buf,nrifaces[fp->interface].interface->name) ;
  531.             if (column++ == 4) {
  532.                 printf("\n") ;
  533.                 column = 1 ;
  534.             }
  535.         }
  536.  
  537.     if (column != 1)
  538.         printf("\n") ;
  539.  
  540.     return 0 ;
  541. }
  542.  
  543. /* add an entry to the filter table */
  544. static
  545. donfadd(argc,argv)
  546. int argc ;
  547. char *argv[] ;
  548. {
  549.     struct ax25_addr neighbor ;
  550.     register int i ;
  551.  
  552.     /* format callsign */
  553.     if (setcall(&neighbor,argv[1]) == -1) {
  554.         printf("bad neighbor callsign\n") ;
  555.         return -1 ;
  556.     }
  557.  
  558.     /* find interface */
  559.     for (i = 0 ; i < nr_numiface ; i++)
  560.         if (!strcmp(nrifaces[i].interface->name,argv[2]))
  561.             break ;
  562.     if (i == nr_numiface) {
  563.         printf("Interface \"%s\" not found\n",argv[2]) ;
  564.         return -1 ;
  565.     }
  566.  
  567.     return nr_nfadd(&neighbor,i) ;
  568. }
  569.  
  570. /* drop an entry from the filter table */
  571. static
  572. donfdrop(argc,argv)
  573. int argc ;
  574. char *argv[] ;
  575. {
  576.     struct ax25_addr neighbor ;
  577.     register int i ;
  578.  
  579.     /* format neighbor callsign */
  580.     if (setcall(&neighbor,argv[1]) == -1) {
  581.         printf("bad neighbor callsign\n") ;
  582.         return -1 ;
  583.     }
  584.  
  585.     /* find interface */
  586.     for (i = 0 ; i < nr_numiface ; i++)
  587.         if (!strcmp(nrifaces[i].interface->name,argv[2]))
  588.             break ;
  589.     if (i == nr_numiface) {
  590.         printf("Interface \"%s\" not found\n",argv[2]) ;
  591.         return -1 ;
  592.     }
  593.  
  594.     return nr_nfdrop(&neighbor,i) ;
  595. }
  596.  
  597. /* nodefilter mode subcommand */
  598. static
  599. donfmode(argc,argv)
  600. int argc ;
  601. char *argv[] ;
  602. {
  603.     if (argc < 2) {
  604.         printf("filter mode is ") ;
  605.         switch (nr_nfmode) {
  606.             case NRNF_NOFILTER:
  607.                 printf("none\n") ;
  608.                 break ;
  609.             case NRNF_ACCEPT:
  610.                 printf("accept\n") ;
  611.                 break ;
  612.             case NRNF_REJECT:
  613.                 printf("reject\n") ;
  614.                 break ;
  615.             default:
  616.                 printf("some strange, unknown value\n") ;
  617.         }
  618.         return 0 ;
  619.     }
  620.     
  621.     switch (argv[1][0]) {
  622.         case 'n':
  623.         case 'N':
  624.             nr_nfmode = NRNF_NOFILTER ;
  625.             break ;
  626.         case 'a':
  627.         case 'A':
  628.             nr_nfmode = NRNF_ACCEPT ;
  629.             break ;
  630.         case 'r':
  631.         case 'R':
  632.             nr_nfmode = NRNF_REJECT ;
  633.             break ;
  634.         default:
  635.             printf("modes are: none accept reject\n") ;
  636.             return -1 ;
  637.     }
  638.  
  639.     return 0 ;
  640. }
  641.  
  642.  
  643. /* netrom network packet time-to-live initializer */
  644. static
  645. donrttl(argc, argv)
  646. int argc ;
  647. char *argv[] ;
  648. {
  649.     int val ;
  650.  
  651.     if (argc < 2) {
  652.         printf("%d\n", nr_ttl) ;
  653.         return 0 ;
  654.     }
  655.  
  656.     val = atoi(argv[1]) ;
  657.  
  658.     if (val < 0 || val > 255) {
  659.         printf("ttl must be between 0 and 255\n") ;
  660.         return 1 ;
  661.     }
  662.  
  663.     nr_ttl = val ;
  664.  
  665.     return 0 ;
  666. }
  667.  
  668. /* verbose route broadcast */
  669. static
  670. donrverbose(argc,argv)
  671. int argc ;
  672. char *argv[] ;
  673. {
  674.     if (argc < 2) {
  675.         printf("verbose is %s\n", nr_verbose ? "yes" : "no" ) ;
  676.         return 0 ;
  677.     }
  678.     
  679.     switch (argv[1][0]) {
  680.         case 'n':
  681.         case 'N':
  682.             nr_verbose = 0 ;
  683.             break ;
  684.         case 'y':
  685.         case 'Y':
  686.             nr_verbose = 1 ;
  687.             break ;
  688.         default:
  689.             printf("use: netrom verbose [yes|no]\n") ;
  690.             return -1 ;
  691.     }
  692.  
  693.     return 0 ;
  694. }
  695.  
  696. /* Initiate a NET/ROM transport connection */
  697. static int
  698. donrconnect(argc,argv)
  699. int argc ;
  700. char *argv[] ;
  701. {
  702.     struct ax25_addr node, *np ;
  703.     struct nr4cb *cb ;
  704.     struct session *s ;
  705.     char alias[7] ;
  706.  
  707.     /* See if the requested destination could be an alias, and */
  708.     /* find and use it if it is.  Otherwise assume it is an ax.25 */
  709.     /* address. */
  710.     
  711.     if (putalias(alias,argv[1],0) != -1 &&
  712.         (np = find_nralias(alias)) != NULLAXADDR)
  713.           node = *np ;
  714.     else
  715.         setcall(&node,argv[1]) ;    /* parse ax25 callsign */
  716.  
  717.     /* Get a session descriptor */
  718.  
  719.     if ((s = newsession()) == NULLSESSION) {
  720.         printf("Too many sessions\n") ;
  721.         return 1 ;
  722.     }
  723.  
  724.     if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  725.         strcpy(s->name,argv[1]);
  726.     s->type = NRSESSION ;
  727.     s->parse = nr4_parse ;
  728.     current = s;
  729.  
  730.     s->cb.nr4_cb = open_nr4(&node,&mycall,nr4_rx,nr4_tx,nr4_state,(char *)s) ;
  731.     go() ;
  732.     return 0 ;
  733. }
  734.  
  735. /* Display changes in NET/ROM state */
  736. void
  737. nr4_state(cb,old,new)
  738. struct nr4cb *cb ;
  739. int old,new;
  740. {
  741.     struct session *s;
  742.  
  743.     s = (struct session *)cb->puser;
  744.  
  745.     if(current != NULLSESSION && current->type == NRSESSION && current == s){
  746.         printf("%s",Nr4states[new]);
  747.         if(new == NR4STDISC) {
  748.             printf(" (%s)\n", Nr4reasons[cb->dreason]) ;
  749.             cmdmode();
  750.         } else
  751.             printf("\n") ;
  752.         fflush(stdout);
  753.     }
  754.     if(new == NR4STDISC){
  755.         cb->puser = NULLCHAR;
  756.         freesession(s);
  757.     }
  758. }
  759.  
  760. /* Handle typed characters on a NET/ROM connection */
  761. void
  762. nr4_parse(buf,cnt)
  763. char *buf;
  764. int16 cnt;
  765. {
  766.     struct mbuf *bp;
  767.     register char *cp;
  768.     int16 size, i ;
  769.     char c;
  770.  
  771.     if(current == NULLSESSION || current->type != NRSESSION)
  772.         return;    /* "can't happen" */
  773.  
  774.     /* If recording is on, record outgoing stuff too */
  775.     if(current->record != NULLFILE)
  776.         fwrite(buf,1,cnt,current->record);
  777.  
  778.     /* Parse it out, splitting at transport frame boundaries */
  779.     
  780.     while (cnt != 0) {
  781. #ifdef NRDEBUG
  782.         printf("Once around the parse loop - cnt = %d\n", cnt) ;
  783. #endif
  784.         size = min(cnt, NR4MAXINFO) ;
  785.         if ((bp = alloc_mbuf(size)) == NULLBUF)
  786.             break ;
  787.         /* Copy keyboard buffer to output, stripping line feeds */
  788.         cp = bp->data ;
  789.         for (i = 0 ; i < size ; i++){
  790.             c = *buf++;
  791.             if(c != '\n'){
  792.                 *cp++ = c;
  793.                 bp->cnt++;
  794.             }
  795.         }
  796.         cnt -= size ;
  797.         send_nr4(current->cb.nr4_cb,bp);
  798.     }
  799. }
  800.  
  801. /* Handle new incoming terminal sessions
  802.  * This is the default state change upcall function, used when
  803.  * someone else connects to us
  804.  */
  805. void
  806. nr4_incom(cb,oldstate,newstate)
  807. struct nr4cb *cb ;
  808. int oldstate ;
  809. int newstate ;
  810. {
  811.     void nr4_session() ;
  812.  
  813.     if (newstate != NR4STCON)        /* why are you bothering us? */
  814.         return ;                    /* (shouldn't happen) */
  815.         
  816.     if (ax25mbox)
  817.         mbx_nr4incom(cb) ;
  818.     else
  819.         nr4_session(cb) ;
  820.     return ;
  821.  
  822. }
  823.  
  824. /* This function sets up a NET/ROM chat session */
  825. void
  826. nr4_session(cb)
  827. struct nr4cb *cb ;
  828. {
  829.     struct session *s;
  830.     char remote[10];
  831.  
  832.     pax25(remote,&cb->user);
  833.     if((s = newsession()) == NULLSESSION){
  834.         /* Out of sessions */
  835.         disc_nr4(cb);
  836.         return;
  837.     }
  838.     s->type = NRSESSION ;
  839.     s->name = malloc((int16)strlen(remote)+1);
  840.     s->cb.nr4_cb = cb ;
  841.     s->parse = nr4_parse;
  842.     strcpy(s->name,remote);
  843.     cb->r_upcall = nr4_rx;
  844.     cb->s_upcall = nr4_state;
  845.     cb->t_upcall = nr4_tx;
  846.     cb->puser = (char *)s;
  847. #if    (defined(MAC) || defined(AMIGA))
  848.     printf("\007Incoming NET/ROM session %lu from %s\n",s - sessions,remote);
  849. #else
  850.     printf("\007Incoming NET/ROM session %u from %s\n",s - sessions,remote);
  851. #endif
  852.     fflush(stdout);
  853. }
  854.  
  855. /* Handle incoming terminal traffic */
  856. void
  857. nr4_rx(cb,cnt)
  858. struct nr4cb *cb ;
  859. int16 cnt;
  860. {
  861.     register struct mbuf *bp;
  862.     char c;
  863.  
  864.     /* Hold output if we're not the current session */
  865.     if(mode != CONV_MODE || current == NULLSESSION
  866.      || current->type != NRSESSION || current->cb.nr4_cb != cb)
  867.         return;
  868.  
  869.     if((bp = recv_nr4(cb,cnt)) == NULLBUF)
  870.         return;
  871.  
  872.     /* Display received characters, translating CR's to CR/LF */
  873.     while(bp != NULLBUF){
  874.         while(bp->cnt-- != 0){
  875.             c = *bp->data++;
  876.             if(c == '\r')
  877.                 c = '\n';
  878.             putchar(c);
  879.             if(current->record){
  880. #ifndef UNIX
  881.                 if(c == '\n')
  882.                     fputc('\r',current->record);
  883. #endif
  884.                 fputc(c,current->record);
  885.             }
  886.         }
  887.         bp = free_mbuf(bp);
  888.     }
  889.     if(current->record)
  890.         fflush(current->record);
  891.     fflush(stdout);
  892. }
  893.  
  894. /* Handle transmit upcalls. Used only for file uploading */
  895. void
  896. nr4_tx(cb,cnt)
  897. struct nr4cb *cb ;
  898. int16 cnt;
  899. {
  900.     register char *cp;
  901.     struct session *s;
  902.     register struct mbuf *bp;
  903.     int16 size;
  904.     int c;
  905.  
  906.     if((s = (struct session *)cb->puser) == NULLSESSION
  907.      || s->upload == NULLFILE)
  908.         return;
  909.     while(cnt != 0){
  910.         size = min(cnt,NR4MAXINFO);
  911.         if((bp = alloc_mbuf(size)) == NULLBUF)
  912.             break;
  913.         cp = bp->data;
  914.  
  915.         /* Now send data characters, translating between local
  916.          * keyboard end-of-line sequences and the (unwritten)
  917.          * AX.25 convention, which is carriage-return only
  918.          */
  919.          
  920.         while(bp->cnt < size){
  921.             if((c = getc(s->upload)) == EOF)
  922.                 break;
  923. #ifdef    MSDOS
  924.             /* MS-DOS gives cr-lf */
  925.             if(c == '\n')
  926.                 continue;
  927. #endif
  928. #if    (defined(UNIX) || defined(MAC) || defined(AMIGA))
  929.             /* These give lf only */
  930.             if(c == '\n')
  931.                 c = '\r';
  932. #endif
  933.             *cp++ = c;
  934.             bp->cnt++;
  935.         }    
  936.         cnt -= bp->cnt;
  937.         
  938.         if (bp->cnt != 0)    /* might happen with a newline at EOF */
  939.             send_nr4(cb,bp);
  940.         else
  941.             free_p(bp) ;
  942.             
  943.         if (c == EOF)
  944.             break ;
  945.     }
  946.     if(cnt != 0){
  947.         /* Error or end-of-file */
  948.         fclose(s->upload);
  949.         s->upload = NULLFILE;
  950.         free(s->ufile);
  951.         s->ufile = NULLCHAR;
  952.     }
  953. }
  954.  
  955. /* Reset a net/rom connection abruptly */
  956.  
  957. static int
  958. donrreset(argc,argv)
  959. int argc;
  960. char *argv[];
  961. {
  962.     struct nr4cb *cb ;
  963.     extern char notval[];
  964.  
  965.     cb = (struct nr4cb *)htol(argv[1]);
  966.     if(!nr4valcb(cb)){
  967.         printf(notval);
  968.         return 1;
  969.     }
  970.     reset_nr4(cb);
  971.     return 0;
  972. }
  973.  
  974. /* Force retransmission on a net/rom connection */
  975.  
  976. static int
  977. donrkick(argc,argv)
  978. int argc;
  979. char *argv[];
  980. {
  981.     struct nr4cb *cb ;
  982.     extern char notval[];
  983.  
  984.     cb = (struct nr4cb *)htol(argv[1]);
  985.  
  986.     if (kick_nr4(cb) == -1) {
  987.         printf(notval);
  988.         return 1;
  989.     } else
  990.         return 0;
  991. }
  992.  
  993. /* netrom transport ACK delay timer */
  994.  
  995. static
  996. donracktime(argc, argv)
  997. int argc ;
  998. char *argv[] ;
  999. {
  1000.     long val ;
  1001.  
  1002.     if (argc < 2) {
  1003.         printf("%lu\n", Nr4acktime) ;
  1004.         return 0 ;
  1005.     }
  1006.  
  1007.     val = atol(argv[1]) ;
  1008.  
  1009.     Nr4acktime = val ;
  1010.  
  1011.     return 0 ;
  1012. }
  1013.  
  1014. /* netrom transport choke timeout */
  1015.  
  1016. static
  1017. donrchoketime(argc, argv)
  1018. int argc ;
  1019. char *argv[] ;
  1020. {
  1021.     long val ;
  1022.  
  1023.     if (argc < 2) {
  1024.         printf("%lu\n", Nr4choketime) ;
  1025.         return 0 ;
  1026.     }
  1027.  
  1028.     val = atol(argv[1]) ;
  1029.  
  1030.     Nr4choketime = val ;
  1031.  
  1032.     return 0 ;
  1033. }
  1034.  
  1035. /* netrom transport initial round trip time */
  1036.  
  1037. static
  1038. donrirtt(argc, argv)
  1039. int argc ;
  1040. char *argv[] ;
  1041. {
  1042.     long val ;
  1043.  
  1044.     if (argc < 2) {
  1045.         printf("%lu\n", Nr4irtt) ;
  1046.         return 0 ;
  1047.     }
  1048.  
  1049.     val = atol(argv[1]) ;
  1050.  
  1051.     Nr4irtt = val ;
  1052.  
  1053.     return 0 ;
  1054. }
  1055.  
  1056. /* netrom transport receive queue length limit.  This is the */
  1057. /* threshhold at which we will CHOKE the sender. */
  1058.  
  1059. static
  1060. donrqlimit(argc, argv)
  1061. int argc ;
  1062. char *argv[] ;
  1063. {
  1064.     unsigned val ;
  1065.  
  1066.     if (argc < 2) {
  1067.         printf("%u\n", Nr4qlimit) ;
  1068.         return 0 ;
  1069.     }
  1070.  
  1071.     val = atoi(argv[1]) ;
  1072.  
  1073.     if (val == 0) {
  1074.         printf("You cannot set the queue limit to 0\n") ;
  1075.         return 1 ;
  1076.     }
  1077.     
  1078.     Nr4qlimit = val ;
  1079.  
  1080.     return 0 ;
  1081. }
  1082.  
  1083. /* netrom transport maximum window.  This is the largest send and */
  1084. /* receive window we may negotiate */
  1085.  
  1086. static
  1087. donrwindow(argc, argv)
  1088. int argc ;
  1089. char *argv[] ;
  1090. {
  1091.     unsigned val ;
  1092.  
  1093.     if (argc < 2) {
  1094.         printf("%u\n", Nr4window) ;
  1095.         return 0 ;
  1096.     }
  1097.  
  1098.     val = atoi(argv[1]) ;
  1099.  
  1100.     if (val == 0 || val > NR4MAXWIN) {
  1101.         printf("Illegal NET/ROM window size.  Range is [1,%d]\n",
  1102.                NR4MAXWIN) ;
  1103.         return 1 ;
  1104.     }
  1105.     
  1106.     Nr4window = val ;
  1107.  
  1108.     return 0 ;
  1109. }
  1110.  
  1111. /* netrom transport maximum retries.  This is used in connect and */
  1112. /* disconnect attempts; I haven't decided what to do about actual */
  1113. /* data retries yet. */
  1114.  
  1115. static
  1116. donrretries(argc, argv)
  1117. int argc ;
  1118. char *argv[] ;
  1119. {
  1120.     unsigned val ;
  1121.  
  1122.     if (argc < 2) {
  1123.         printf("%u\n", Nr4retries) ;
  1124.         return 0 ;
  1125.     }
  1126.  
  1127.     val = atoi(argv[1]) ;
  1128.  
  1129.     if (val == 0) {
  1130.         printf("Impatient, aren't we?  Zero retries not possible\n") ;
  1131.         return 1 ;
  1132.     }
  1133.     
  1134.     Nr4retries = val ;
  1135.  
  1136.     return 0 ;
  1137. }
  1138.  
  1139. /* Display the status of NET/ROM connections */
  1140.  
  1141. static
  1142. donrstatus(argc, argv)
  1143. int argc ;
  1144. char *argv[] ;
  1145. {
  1146.     int i ;
  1147.     struct nr4cb *cb ;
  1148.     char luser[10], ruser[10], node[10] ;
  1149.     extern char notval[] ;
  1150.     void donrdump() ;
  1151.     
  1152.     if (argc < 2) {
  1153.         printf("     &CB Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  1154.         for (i = 0 ; i < NR4MAXCIRC ; i++) {
  1155.             if ((cb = Nr4circuits[i].ccb) == NULLNR4CB)
  1156.                 continue ;
  1157.             pax25(luser,&cb->luser) ;
  1158.             pax25(ruser,&cb->user) ;
  1159.             pax25(node,&cb->node) ;
  1160.             printf("%8lx   %3d %5d %5d %9s  %9s %-9s %s\n",
  1161.                    (long)cb, cb->nbuffered, len_q(cb->txq),
  1162.                    len_mbuf(cb->rxq), luser, ruser, node,
  1163.                    Nr4states[cb->state]) ;
  1164.         }
  1165.         return 0 ;
  1166.     }
  1167.  
  1168.     cb = (struct nr4cb *)htol(argv[1]) ;
  1169.     if (!nr4valcb(cb)) {
  1170.         printf(notval) ;
  1171.         return 1 ;
  1172.     }
  1173.  
  1174.     donrdump(cb) ;
  1175.     return 0 ;
  1176. }
  1177.  
  1178. /* Dump one control block */
  1179.  
  1180. static void
  1181. donrdump(cb)
  1182. struct nr4cb *cb ;
  1183. {
  1184.     int i ;
  1185.     char luser[10], ruser[10], node[10] ;
  1186.     unsigned seq ;
  1187.     struct nr4txbuf *b ;
  1188.     struct timer *t ;
  1189.  
  1190.     pax25(luser,&cb->luser) ;
  1191.     pax25(ruser,&cb->user) ;
  1192.     pax25(node, &cb->node) ;
  1193.  
  1194.     printf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
  1195.            luser, cb->mynum, cb->myid, ruser, node,
  1196.            cb->yournum, cb->yourid, Nr4states[cb->state]) ;
  1197.  
  1198.     printf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
  1199.            cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
  1200.            len_mbuf(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
  1201.  
  1202.     printf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\n",
  1203.            cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
  1204.            len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
  1205.  
  1206.     printf("TACK: ") ;
  1207.     if (run_timer(&cb->tack))
  1208.         printf("%lu", (cb->tack.start - cb->tack.count) * MSPTICK) ;
  1209.     else
  1210.         printf("stop") ;
  1211.     printf("/%lu ms; ", cb->tack.start * MSPTICK) ;
  1212.  
  1213.     printf("TChoke: ") ;
  1214.     if (run_timer(&cb->tchoke))
  1215.         printf("%lu", (cb->tchoke.start - cb->tchoke.count) * MSPTICK) ;
  1216.     else
  1217.         printf("stop") ;
  1218.     printf("/%lu ms; ", cb->tchoke.start * MSPTICK) ;
  1219.  
  1220.     printf("TCD: ") ;
  1221.     if (run_timer(&cb->tcd))
  1222.         printf("%lu", (cb->tcd.start - cb->tcd.count) * MSPTICK) ;
  1223.     else
  1224.         printf("stop") ;
  1225.     printf("/%lu ms", cb->tcd.start * MSPTICK) ;
  1226.  
  1227.     if (run_timer(&cb->tcd))
  1228.         printf("; Tries: %u\n", cb->cdtries) ;
  1229.     else
  1230.         printf("\n") ;
  1231.  
  1232.     printf("Backoff Level %u SRTT %ld ms Mean dev %ld ms\n",
  1233.            cb->blevel, cb->srtt, cb->mdev) ;
  1234.  
  1235.     /* If we are connected and the send window is open, display */
  1236.     /* the status of all the buffers and their timers */
  1237.     
  1238.     if (cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
  1239.  
  1240.         printf("TxBuffers:  Seq  Size  Tries  Timer\n") ;
  1241.  
  1242.         for (seq = cb->ackxpected ;
  1243.              nr4between(cb->ackxpected, seq, cb->nextosend) ;
  1244.              seq = (seq + 1) & NR4SEQMASK) {
  1245.  
  1246.             b = &cb->txbufs[seq % cb->window] ;
  1247.             t = &b->tretry ;
  1248.  
  1249.             printf("            %3u   %3d  %5d  %lu/%lu\n",
  1250.                    seq, len_mbuf(b->data), b->retries + 1,
  1251.                    (t->start - t->count) * MSPTICK, t->start * MSPTICK) ;
  1252.         }
  1253.  
  1254.     }
  1255.  
  1256. }
  1257.